{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Deep Learning"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "pd.set_option(\"display.max_rows\",15)\n",
    "%matplotlib inline\n",
    "\n",
    "sess = tf.InteractiveSession()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "tf.reset_default_graph()\n",
    "\n",
    "input_dim = 122\n",
    "classes = 2\n",
    "hidden_encoder_dim = 80\n",
    "\n",
    "latent_dim = 10\n",
    "\n",
    "hidden_decoder_dim = 80\n",
    "\n",
    "lam = 0.01\n",
    "\n",
    "def weight_variable(shape):\n",
    "    initial = tf.truncated_normal(shape, stddev=0.001)\n",
    "    return tf.Variable(initial)\n",
    "\n",
    "def bias_variable(shape):\n",
    "    initial = tf.constant(0.01, shape=shape)\n",
    "    return tf.Variable(initial)\n",
    "\n",
    "l2_loss = tf.constant(0.001)\n",
    "#learning_rate = tf.Variable(initial_value=0.001)\n",
    "\n",
    "with tf.variable_scope(\"Input\"):\n",
    "    x = tf.placeholder(\"float\", shape=[None, input_dim])\n",
    "    y_ = tf.placeholder(\"float\", shape=[None, classes])\n",
    "    \n",
    "    keep_prob = tf.placeholder(\"float\")\n",
    "\n",
    "with tf.variable_scope(\"Layer_Encoder\"):\n",
    "    W_encoder_input_hidden = weight_variable([input_dim,hidden_encoder_dim])\n",
    "    b_encoder_input_hidden = bias_variable([hidden_encoder_dim])\n",
    "    l2_loss += tf.nn.l2_loss(W_encoder_input_hidden)\n",
    "\n",
    "    # Hidden layer encoder\n",
    "    hidden_encoder = tf.nn.relu(tf.matmul(x, W_encoder_input_hidden) + b_encoder_input_hidden)\n",
    "    tf.summary.histogram(\"Weights_Encoder\", W_encoder_input_hidden)\n",
    "    hidden_encoder = tf.nn.dropout(hidden_encoder, keep_prob=keep_prob)\n",
    "\n",
    "with tf.variable_scope(\"Layer_Mean\"):\n",
    "    W_encoder_hidden_mu = weight_variable([hidden_encoder_dim,latent_dim])\n",
    "    b_encoder_hidden_mu = bias_variable([latent_dim])\n",
    "    l2_loss += tf.nn.l2_loss(W_encoder_hidden_mu)\n",
    "\n",
    "    # Mu encoder\n",
    "    mu_encoder = tf.matmul(hidden_encoder, W_encoder_hidden_mu) + b_encoder_hidden_mu\n",
    "    tf.summary.histogram(\"Weights_Mean\", W_encoder_hidden_mu)\n",
    "\n",
    "with tf.variable_scope(\"Layer_Variance\"):\n",
    "    W_encoder_hidden_logvar = weight_variable([hidden_encoder_dim,latent_dim])\n",
    "    b_encoder_hidden_logvar = bias_variable([latent_dim])\n",
    "    l2_loss += tf.nn.l2_loss(W_encoder_hidden_logvar)\n",
    "\n",
    "    # Sigma encoder\n",
    "    logvar_encoder = tf.matmul(hidden_encoder, W_encoder_hidden_logvar) + b_encoder_hidden_logvar\n",
    "    tf.summary.histogram(\"Weights_Variance\", W_encoder_hidden_logvar)\n",
    "\n",
    "with tf.variable_scope(\"Sampling_Distribution\"):\n",
    "    # Sample epsilon\n",
    "    epsilon = tf.random_normal(tf.shape(logvar_encoder), name='epsilon')\n",
    "\n",
    "    # Sample latent variable\n",
    "    std_encoder = tf.exp(0.5 * logvar_encoder)\n",
    "    z = mu_encoder + tf.multiply(std_encoder, epsilon)\n",
    "    tf.summary.histogram(\"Sample_Distribution\", z)\n",
    "    \n",
    "with tf.variable_scope(\"Layer_Decoder\"):\n",
    "    W_decoder_z_hidden = weight_variable([latent_dim,hidden_decoder_dim])\n",
    "    b_decoder_z_hidden = bias_variable([hidden_decoder_dim])\n",
    "    l2_loss += tf.nn.l2_loss(W_decoder_z_hidden)\n",
    "\n",
    "    # Hidden layer decoder\n",
    "    hidden_decoder = tf.nn.relu(tf.matmul(z, W_decoder_z_hidden) + b_decoder_z_hidden)\n",
    "    hidden_decoder = tf.nn.dropout(hidden_decoder, keep_prob=keep_prob)\n",
    "    tf.summary.histogram(\"Weights_Decoder\", W_decoder_z_hidden)\n",
    "\n",
    "with tf.variable_scope(\"Layer_Reconstruction\"):\n",
    "    W_decoder_hidden_reconstruction = weight_variable([hidden_decoder_dim, input_dim])\n",
    "    b_decoder_hidden_reconstruction = bias_variable([input_dim])\n",
    "    l2_loss += tf.nn.l2_loss(W_decoder_hidden_reconstruction)\n",
    "\n",
    "    x_hat = tf.matmul(hidden_decoder, W_decoder_hidden_reconstruction) + b_decoder_hidden_reconstruction\n",
    "    tf.summary.histogram(\"Weights_Reconstruction\", W_decoder_hidden_reconstruction)\n",
    "\n",
    "with tf.variable_scope(\"Layer_Dense_Hidden\"):\n",
    "    hidden_output = tf.layers.dense(z,latent_dim, activation=tf.nn.relu)\n",
    "\n",
    "with tf.variable_scope(\"Layer_Dense_Softmax\"):\n",
    "    y = tf.layers.dense(z, classes, activation=tf.nn.softmax)\n",
    "    \n",
    "with tf.variable_scope(\"Loss\"):\n",
    "    BCE = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=x_hat, labels=x), reduction_indices=1)\n",
    "    KLD = -0.5 * tf.reduce_mean(1 + logvar_encoder - tf.pow(mu_encoder, 2) - tf.exp(logvar_encoder), reduction_indices=1)\n",
    "    softmax_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y_, logits = y))\n",
    "    \n",
    "    loss = tf.reduce_mean(BCE + KLD + softmax_loss)\n",
    "\n",
    "    regularized_loss = tf.abs(loss + lam * l2_loss, name = \"Regularized_loss\")\n",
    "    correct_prediction = tf.equal(tf.argmax(y_, 1), tf.argmax(y, 1))\n",
    "    tf_accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32), name = \"Accuracy\")\n",
    "    \n",
    "    pred = tf.argmax(y, 1)\n",
    "    actual = tf.argmax(y_, 1)\n",
    "    \n",
    "    #tf.summary.scalar(\"BCE\", BCE)\n",
    "    #tf.summary.scalar(\"KLD\", KLD)\n",
    "    #tf.summary.scalar(\"Softmax_loss\", softmax_loss)\n",
    "    \n",
    "    tf.summary.scalar(\"loss\", regularized_loss)\n",
    "    \n",
    "with tf.variable_scope(\"Optimizer\"):\n",
    "    learning_rate=0.001\n",
    "    grad_clip=5\n",
    "    tvars = tf.trainable_variables()\n",
    "    grads, _ = tf.clip_by_global_norm(tf.gradients(regularized_loss, tvars), grad_clip)\n",
    "    train_op = tf.train.AdamOptimizer(learning_rate)\n",
    "    optimizer = train_op.apply_gradients(zip(grads, tvars))\n",
    "    \n",
    "# add op for merging summary\n",
    "summary_op = tf.summary.merge_all()\n",
    "\n",
    "# add Saver ops\n",
    "# saver = tf.train.Saver()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "kdd_train_2labels = pd.read_pickle(\"dataset/kdd_train_2labels.pkl\")\n",
    "kdd_test_2labels = pd.read_pickle(\"dataset/kdd_test_2labels.pkl\")\n",
    "\n",
    "\n",
    "output_columns_2labels = ['is_Attack','is_Normal']\n",
    "\n",
    "from sklearn import model_selection as ms\n",
    "from sklearn import preprocessing as pp\n",
    "\n",
    "x_input = kdd_train_2labels.drop(output_columns_2labels, axis = 1)\n",
    "y_output = kdd_train_2labels.loc[:,output_columns_2labels]\n",
    "\n",
    "ss = pp.StandardScaler()\n",
    "\n",
    "x_input = ss.fit_transform(x_input)\n",
    "\n",
    "x_train, x_valid, y_train, y_valid = ms.train_test_split(x_input, \n",
    "                              y_output.values, \n",
    "                              test_size=0.2)\n",
    "#x_valid, x_test, y_valid, y_test = ms.train_test_split(x_valid, y_valid, test_size = 0.4)\n",
    "\n",
    "x_test = kdd_test_2labels.drop(output_columns_2labels, axis = 1)\n",
    "y_test = kdd_test_2labels.loc[:,output_columns_2labels]\n",
    "\n",
    "x_test = ss.transform(x_test)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Step 0 | Training Loss: 0.8612 | Validation Accuracy: 0.9096\n",
      "Step 2 | Training Loss: 0.0390 | Validation Accuracy: 0.8969\n",
      "Step 4 | Training Loss: 0.0406 | Validation Accuracy: 0.9065\n",
      "Step 6 | Training Loss: 0.0852 | Validation Accuracy: 0.9110\n",
      "Step 8 | Training Loss: 0.0646 | Validation Accuracy: 0.9021\n",
      "Step 10 | Training Loss: 0.0663 | Validation Accuracy: 0.8974\n",
      "Step 12 | Training Loss: 0.1153 | Validation Accuracy: 0.8836\n",
      "Step 14 | Training Loss: 0.0218 | Validation Accuracy: 0.8867\n",
      "Step 16 | Training Loss: 0.0103 | Validation Accuracy: 0.8995\n",
      "Step 18 | Training Loss: 0.0021 | Validation Accuracy: 0.8964\n",
      "Step 20 | Training Loss: 0.0046 | Validation Accuracy: 0.8972\n",
      "Step 22 | Training Loss: 0.0426 | Validation Accuracy: 0.8981\n",
      "Step 24 | Training Loss: 0.0106 | Validation Accuracy: 0.8918\n",
      "Step 26 | Training Loss: 0.0030 | Validation Accuracy: 0.8987\n",
      "Step 28 | Training Loss: 0.0515 | Validation Accuracy: 0.9045\n",
      "Step 30 | Training Loss: 0.0419 | Validation Accuracy: 0.9030\n",
      "Step 32 | Training Loss: 0.0537 | Validation Accuracy: 0.9086\n",
      "Step 34 | Training Loss: 0.0074 | Validation Accuracy: 0.8941\n",
      "Step 36 | Training Loss: 0.0139 | Validation Accuracy: 0.8945\n",
      "Step 38 | Training Loss: 0.0498 | Validation Accuracy: 0.8942\n",
      "Accuracy on Test data: 0.7195706367492676\n"
     ]
    }
   ],
   "source": [
    "epochs = 40\n",
    "batch_iterations = 100\n",
    "\n",
    "batch_indices = np.array_split(np.arange(x_train.shape[0]), batch_iterations)\n",
    "\n",
    "with tf.Session() as sess:\n",
    "    summary_writer_train = tf.summary.FileWriter('./logs/kdd/VAE/training', graph=sess.graph)\n",
    "    summary_writer_valid = tf.summary.FileWriter('./logs/kdd/VAE/validation')\n",
    "\n",
    "    sess.run(tf.global_variables_initializer())\n",
    "\n",
    "    for epoch in range(0, epochs):\n",
    "        for i in batch_indices:\n",
    "            _, train_loss, summary_str = sess.run([optimizer, regularized_loss, summary_op],\n",
    "                                                  feed_dict={x: x_train[i,:], y_: y_train[i,:], keep_prob:0.6})\n",
    "            summary_writer_train.add_summary(summary_str, epoch)\n",
    "\n",
    "        \n",
    "        accuracy, summary_str = sess.run([tf_accuracy, summary_op], \n",
    "                                              feed_dict={x: x_valid, y_:y_valid, keep_prob:1})\n",
    "        summary_writer_valid.add_summary(summary_str, epoch)\n",
    "            \n",
    "        if epoch % 2 == 0:\n",
    "            print(\"Step {} | Training Loss: {:.4f} | Validation Accuracy: {:.4f}\".format(epoch, train_loss, accuracy))\n",
    "            \n",
    "    accuracy, pred_value, actual_value = sess.run([tf_accuracy, pred, actual], feed_dict={x: x_test, y_:y_test, keep_prob:1})\n",
    "    \n",
    "    print(\"Accuracy on Test data: {}\".format(accuracy))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import itertools\n",
    "\n",
    "def plot_confusion_matrix(cm, classes,\n",
    "                          normalize=False,\n",
    "                          title='Confusion matrix',\n",
    "                          cmap=plt.cm.Blues):\n",
    "    \"\"\"\n",
    "    This function prints and plots the confusion matrix.\n",
    "    Normalization can be applied by setting `normalize=True`.\n",
    "    \"\"\"\n",
    "    np.set_printoptions(precision=4)\n",
    "\n",
    "    plt.imshow(cm, interpolation='nearest', cmap=cmap)\n",
    "    plt.title(title)\n",
    "    plt.colorbar()\n",
    "    tick_marks = np.arange(len(classes))\n",
    "    plt.xticks(tick_marks, classes, rotation=45)\n",
    "    plt.yticks(tick_marks, classes)\n",
    "\n",
    "    if normalize:\n",
    "        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n",
    "        print(\"Normalized confusion matrix\")\n",
    "    else:\n",
    "        print('Confusion matrix, without normalization')\n",
    "\n",
    "    print(cm)\n",
    "\n",
    "    thresh = cm.max() / 2.\n",
    "    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n",
    "        plt.text(j, i, cm[i, j].round(4),\n",
    "                 horizontalalignment=\"center\",\n",
    "                 color=\"white\" if cm[i, j] > thresh else \"black\")\n",
    "\n",
    "    plt.tight_layout()\n",
    "    plt.ylabel('True label')\n",
    "    plt.xlabel('Predicted label')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Normalized confusion matrix\n",
      "[[ 0.5414  0.4586]\n",
      " [ 0.045   0.955 ]]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nINakYnklL4/9PTv86ELade3JxN8eybpf2I2OvTf+XL6pd1xG9y13+tw9Bp10KW06dl0p7dV/XMom\n+42kx8AvMnfKY0z9x6UMPvkyllcu44Ux57D14b+gU9/+fPrRfCpa+U9Z3VZ5dv0WywNFbIVtNuzK\nW/M+5p33P2FpZXDXMzPZc2DPBl+/Xpd27LHluoyd+M5K6a/N+Zg35n5c4zV7DezJ9PcXMXX2RzWe\nt9I3/80X6dCjLx169KGi9Vqst8NezH3uoc/le/u/f6PXtnvQplO3Bt1XiGWLs9+bZZ98RNsuPQB4\n7+VJdOyzGZ369gegTccuqKJVkT5N+ZKKt5UyBzVbYb3O7Zj54eIVx7PmL6ZXl3afy7d9v67889Rd\nuWrkYDbr1XFF+k8P3Irz73qF5Q1cy7ZDm1Yc/ZVNuPi+afVntpK1ZP5c2nb77MtP2249WTJ/5Zr3\n4g/nMOfZ/9J3t29+/gYST158IhN+832mP/KPFcmbf+tkpv7jEh762TCm3n4xmw07FoBFc95GiKcu\nOZkJ543gzftuaJwPZi2S6+y2Sl6csYDdRz/Iok8r2X3Ldbl8xA7sff5DfGWrdXnvoyVMmbGAnTbp\n3qB7nbDPZlzz0Jss+rSy/szWor1y2wX0H3Y8qvj89+gdT7mCdl178unC93nykpNYe72N6LbZ9kx/\n+O9s/s2T6LX9V5j11P28eOP/MeiEi4nKSj54/Vl2/vFfaNWmHU9edAKdNtyCdbbYsRk+WcuRl+bH\nJgtqkh6LiF1W47rtgKeB/SLinpTWFfhORFyWjvsBu0TEX1ezbA8Cp6d1e3Jr1oLF9O76Wc1svS7t\nmD1/8Up5PlqybMX+f1+eyznfGEC3DmuxQ79u7DmgF7tvuS5t12pFx7at+d2h23D6Tc/V+rxtN+jK\n0C+sxxn7b0Hn9muxPIIlSyu54bG3i//hrNG07bIuSz6Ys+J4yQdzaNtl3ZXyLHj7ZZ6/5mwAln40\nn3lTHkcVrei57e6065rV8tp06k7PbXZn/psv0m2z7Zk58W62+NYpAPTafk9e/OuvAWjXtSfdNt1u\nRR9cj4FfZOE7rzio1aUFNBsWS5MFtdUJaMmhwCPp5z0prSvZaqiXpeN+wHeA1Qpqlnn+nfn067E2\nfbu1Z/aCxey/XW9O/euzK+Xp0akN8xZ+CsA2G3ShQuKDRUv5/fhX+f34V4FshOQPdt+4zoAG8J3L\n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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f23dc0577b8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "cm_2labels = confusion_matrix(y_pred = pred_value, y_true = actual_value)\n",
    "plt.figure(figsize=[6,6])\n",
    "plot_confusion_matrix(cm_2labels, output_columns_2labels, normalize = True)"
   ]
  }
 ],
 "metadata": {
  "_draft": {
   "nbviewer_url": "https://gist.github.com/441dbeee083527e615728d6d3057ba04"
  },
  "gist": {
   "data": {
    "description": "With Truth Table: Getting 90% accuracy with KDDTest+",
    "public": false
   },
   "id": "441dbeee083527e615728d6d3057ba04"
  },
  "kernelspec": {
   "display_name": "Python [conda env:p3]",
   "language": "python",
   "name": "conda-env-p3-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
